home *** CD-ROM | disk | FTP | other *** search
/ Amiga Packmags / NewsFlash - Issue 07 (1990-01)(UGA - 17-Bit Software)(Disk 1 of 2)[a].zip / NewsFlash - Issue 07 (1990-01)(UGA - 17-Bit Software)(Disk 1 of 2)[a].adf / prog / tp.doc < prev   
Text File  |  1988-01-19  |  20KB  |  462 lines

  1. The TP (TyPe) project for UGA newsletter. First Chapter.
  2. Author: Jeroen K Sparla
  3. In 3 issues for the UGA newsletter, we will create 3 programs,
  4. one written in the language C, and two written in assembly, for
  5. displaying documentation files.
  6.  
  7. With this three programs you're able to display doc files in a
  8. no-nonsence fast and efficient way.
  9. Our goal is to create a utility that converts a ascii-docfile into
  10. an executable program, in order to display itself.
  11. We are gonna do this job in three stages:
  12. 1) A C-program, intended for the amiga-users who do have a certain knowledge
  13.    of the program language C, but are curious how to program the 
  14.    amiga specific things like screens etc.
  15.    This version of TP is rather straightforward and does nothing special,
  16.    if it's a matter in fact, it's quite unusable; but it should show
  17.    in a step by step way how to setup things for the amiga.
  18.    This program is kept short which resulted in a not too nice Amy program.
  19.    If there is any interest i'll rewrite it in a nice Intuition context,
  20.    every bit of code performing a legal job in the intuiton context.
  21.    Routines suchs as the LeftMouseButton() are bad in this multitasking
  22.    environment, and will probably not work with new amiga releases.
  23.    On the other hand, rewritting this program with a full, nice Intuition
  24.    interface will result in a executable about twice as big as this one.
  25.    If you're interested in such an application, fully explained, please
  26.    let me know and i'll write one.
  27.    For the C language refer to books suchs as K&R.(or Ammeraal from academic
  28.    service if you're Dutch).
  29. 2) A 68000 machinecode program performing the same as the C version above.
  30.    Intended for the machinecode freaks amongst you.
  31. 3) The final machinecode version which attaches itself to the docfile turning
  32.    it in a executable which displays itself.
  33.    Tricky code will be used for this one with lots of commandline options.
  34.    There are a few disadventages in this oproach:
  35.    - You can't edit/print/display-in-an-other-way the docfile
  36.      to suit your needs because it's part of an executable.
  37.      An unpack option should cover the problem.
  38.    - The same executable extends each individual doc file, i do not
  39.      think this approach is faster/better than a standalone TP in the
  40.      C directory or in RAM:-disk
  41.    The advantage for a magazine like this is that the executable docfile
  42.    can be crunched; the standalone versions of TP can be crunched ofcourse
  43.    but the ascii-file as an argument can't !
  44.    So the executable method CAN mean winning diskspace IF you crunch.
  45.  
  46. A step by step explanation by the C program (included on this disk, tp.c)
  47. will follow:
  48.  
  49. --------------------------------------------------------------------------------
  50. #define GTX 560  /* Emulated Gadget coordinates topleft & bottomright */
  51. #define GTY 0
  52. #define GBX 579
  53. #define GBY 9
  54.  
  55. In the construction '#define xxx yyy'
  56. xxx will be replaced by yyy during compilation.
  57. --------------------------------------------------------------------------------
  58.  
  59. --------------------------------------------------------------------------------
  60. extern struct Screen *OpenScreen();           /* prototyping for Aztec */
  61.  
  62. We will tell the compiler that the OpenScreen() function will return
  63. a pointer to a screen structure and not to an ordinary integer.
  64. The extern tells the compiler that the function OpenScreen() is not part
  65. of my program but in the extern functionlibrary.
  66. --------------------------------------------------------------------------------
  67.  
  68. --------------------------------------------------------------------------------
  69. LONG IntuitionBase=0L;                        /* pointer to intuition.library */
  70. LONG GfxBase=0L;                              /* pointer to graphics.library */
  71.  
  72. This pointers to libraries are initialised to NULL, so the cleanup routine 
  73. will know what libraries to close. If they are still NULLpointers 
  74. the libraries will not be closed.
  75. --------------------------------------------------------------------------------
  76.  
  77. --------------------------------------------------------------------------------
  78. /* our own screen definitions */
  79. struct NewScreen ns= { 0,0,                   /* top x,y */
  80.                        640,200,1,             /* lower x,y and number of bitplanes */
  81.                        0,1,                   /* detail and block pen */
  82.                        HIRES,                 /* we want a hires screen */
  83.                        CUSTOMSCREEN,          /* not the workbench but our own */
  84.                        NULL,                  /* default font */
  85.                        /* the title */
  86.                        (UBYTE *)"TP(L) V0.9 (c)1989 by Trihedral Systems  -=[YEP]=-",
  87.                        NULL                   /* always null, no screengadgets */
  88.                      };
  89.  
  90. If we want to open a screen, there are two structures involved in it,
  91. the NewScreen structure and the Screen structure.
  92. The NewScreen structure is a subset of the full Screen structure, only
  93. including the values that must be present to open a screen.
  94. A pointer to this structure will be passed to OpenScreen().
  95. OpenScreen returns a pointer to the full Screen structure which contains
  96. information such as your mouse position on that screen.
  97. --------------------------------------------------------------------------------
  98.  
  99. --------------------------------------------------------------------------------
  100. struct RastPort *rp=NULL;                     /* pointer to rasterport */
  101.  
  102. A pointer to the rasterport. Later pointed to the rasterport from the screen.
  103. The rasterport contains information where to find the bitmap(s).
  104. (in our example just one).
  105. This pointer must be passed to every function which want to do something
  106. in/with this bitmaps.
  107. --------------------------------------------------------------------------------
  108.  
  109. --------------------------------------------------------------------------------
  110. struct Screen *screen=NULL;                   /* pointer to screen */
  111.  
  112. A pointer to the Screen structure. Initialised by the OpenScreen() function.
  113. --------------------------------------------------------------------------------
  114.  
  115. --------------------------------------------------------------------------------
  116. FILE  *infile=NULL;                           /* pointer to our ascii textfile */
  117.  
  118. Standard C for getting a filepointer to our text input file.
  119. --------------------------------------------------------------------------------
  120.  
  121. --------------------------------------------------------------------------------
  122. int error=0;                                  /* errornumber during init */
  123. int new=FALSE;                                /* user want to start again ? */
  124. int scndscr=FALSE;                            /* are we past the first screen ? */
  125. int BottomLine;                               /* lowest scanline we want to reach */
  126.  
  127. We will use a few global variables to inform the program about:
  128. error : holds the errornumber when it encounters an error.
  129. new : if TRUE, the user wants to start at the beginning of the file.
  130. scndscr: if TRUE, the user has left the first screen.
  131. BottomLine: contains the number of the last scanline+offset we want to use. 
  132. --------------------------------------------------------------------------------
  133.  
  134. --------------------------------------------------------------------------------
  135. void Init()
  136. { /* try to open the graphics library */
  137.   GfxBase=OpenLibrary("graphics.library",0);
  138.   if(GfxBase==NULL)
  139.   { puts("Can't open graphics.library");
  140.     error=10;
  141.   }
  142.   /* try to open the intuition library */
  143.   IntuitionBase=OpenLibrary("intuition.library",0);
  144.   if(IntuitionBase==NULL)
  145.   { puts("Can't open intuition.library");
  146.     error=20;
  147.   }
  148.  
  149. Opening libraries is a quite standard procedure on the Amiga.
  150. By opening a library you gain access to standard Amiga functions
  151. for performing things like opening screens etc.
  152. We need the graphics library for the Text() and Move() calls for instance.
  153. OpenLibrary() returns the base adress for the jumptable, if it returns
  154. NULL the library couldn't be opened.
  155.  
  156.   /* try to open the new screen */
  157.   screen=OpenScreen(&ns);
  158.   if(screen==NULL)
  159.   { puts("Can't open screen");
  160.     error=30;
  161.   }
  162.  
  163. This piece of code will open the requested screen. If it succeeds it will
  164. return a pointer to the Screen structure. If screen is still NULL, the screen
  165. has failed to open. (too many screens open, no memory for bitmaps....)
  166.  
  167.   /* place screen in front (should be done automaticly.. just in case */
  168.   ScreenToFront(screen);
  169.  
  170. With this routine we ask intuiton to place our screen in front of all the
  171. others. Normally, if a screen is opened it's automaticly placed in front
  172. of the others.
  173.  
  174.   /* initialise pointer to the rasterport from the screen */
  175.   rp = &screen->RastPort;
  176.  
  177. We want to know where to find the rasterport from the screen to pass it
  178. along with the functions who want to know where the bitmaps are.
  179.  
  180.   /* set the drawing pen to the second color (0,1,2...) of the palette */
  181.   SetAPen(rp,1);
  182.  
  183. Since we have only one bitplane asked, we can only choose colors 0 and 1
  184. for the Drawingpen. In our case 0 is the background color and 1 the 
  185. cursorcolor.
  186.  
  187. }
  188. --------------------------------------------------------------------------------
  189.  
  190. -------------------------------------------------------------------------------- 
  191. int LeftMouseButton()
  192. { APTR address=0xbfe000;          /* CIAA, bit 6, 1:released, 0:pressed */ 
  193.                                   /* this should be address 0xbfe001, but */
  194.                                   /* we work on word (2byte) boundaries */
  195.  
  196. The left mousebutton is connected to CIA-A pin 6. The CIA is located in
  197. the memorymap at address 0xbfe001, but since we read words (2 bytes) we
  198. refer to memorylocation 0xbfe000.
  199. I must tell you that this is NOT the way to read the mousebutton in a 
  200. multitasking/multiwindow/multieverything environment, but since there is
  201. no IDCMPport (IntuitionDirectCommunicationsMessagePort) available in this 
  202. program, intuiton can't tell me in a nice way that either mousebutton has
  203. been pressed.
  204.  
  205.   unsigned short Mouse;  
  206.   Mouse=(unsigned short)(*address);        /* fetch data CIAA */
  207.  
  208. Here we read the state of the button.
  209.  
  210.   if((Mouse & 64)==64)                     /* bit 6 set ? */
  211.     return(FALSE);                         /* yes, button not pressed */
  212.   else
  213.     return(TRUE);                          /* no, button is pressed */
  214. }
  215. --------------------------------------------------------------------------------
  216.  
  217. --------------------------------------------------------------------------------
  218. void DrawGadget()
  219. { SetAPen(rp,0);                           /* set drawpen to backgroundcolor */
  220.  
  221. Specify the fill color.
  222.  
  223.   RectFill(rp,GTX,GTY,GBX,GBY);            /* draw filled box */
  224.  
  225. And fill our 'gadget', it's located in the screentitle.
  226.  
  227.   SetAPen(rp,1);                           /* set drawpen to cursorcolor */
  228.  
  229. Specify the drawcolor
  230.  
  231.   Move(rp,GTX+4,GTY+2);                    /* move to topleftedge */
  232.   Draw(rp,GBX-4,GTY+2);                    /* draw interior box */
  233.   Draw(rp,GBX-4,GBY-2);
  234.   Draw(rp,GTX+4,GBY-2);
  235.   Draw(rp,GTX+4,GTY+2);
  236.  
  237. And draw a box.
  238.  
  239. This routine does nothing more than drawing a box within a filled box
  240. if the screentitlebar. It's just a drawing, not a gadget such as intuition
  241. supports. In the routine NextScreen() we wait till the user moved the pointer
  242. in this area and then skip to the next screen.
  243. If i should use a intuition gadget, the code would increase and this is
  244. doing the job as well.
  245. }
  246. --------------------------------------------------------------------------------
  247.  
  248. --------------------------------------------------------------------------------
  249. CLS()
  250. { SetAPen(rp,0);                           /* background color */
  251.   /* fill until scanline 200 if NTSC, in PAL until line 256 */
  252.   RectFill(rp,0,10,639,BottomLine==201 ? 199 : 255);
  253.  
  254. Here is checked if we are clearing a NTSC or a PAL screen.
  255.  
  256.   SetAPen(rp,1);                           /* back to cursor color */
  257.   DrawGadget();                            /* place the gadget, just in case... */
  258.  
  259. And the 'gadget' image is redrawn, just in case it messed up.
  260.  
  261. Clearing the screen by a RectFill() with the background color is quite fast.
  262. }
  263.  
  264.  
  265. --------------------------------------------------------------------------------
  266.  
  267. --------------------------------------------------------------------------------
  268. NextScreen()
  269. { int x,y,hit=FALSE;                /* mouse x,y position and mouseleftbutton */
  270.   new=FALSE;                        /* does the user want to restart */
  271.   while((!hit) && (!new))           /* user didn't take any action */
  272.  
  273. You should recognize this flags.
  274.  
  275.   { hit=LeftMouseButton();          /* left mousebutton ? */
  276.     x=screen->MouseX;               /* fetch mouse coordinates */
  277.     y=screen->MouseY;
  278.  
  279. Here we refer to the Screen structure. We want to know where the mouse-
  280. pointer is located.
  281.  
  282.     /* if the pointer is in our gadget and we are at least at the secondscreen */
  283.     if(x>GTX && x<GBX && y>GTY && y<GBY && scndscr)
  284.       new=TRUE;                     /* the user wants to restart */
  285.  
  286. If the mouse is in our 'gadget' area, the user request us to go to the
  287. beginning of the textfile. 
  288. If this is the first screen displayed, going to the beginning makes no sence
  289. and it provides repeating itself.
  290.  
  291.   }
  292.   CLS();                            /* always clear the screen */
  293.   if(hit && new)                    /* user in gadget and mousebutton pressed */
  294.     error=(90);                     /* user wants to quit */
  295.  
  296. If the user was in the gadgetarea and hit the left mousebutton, he 
  297. requests the main program to cleanup things and quit by specifying
  298. error number 90. (this could really be any number...)
  299.  
  300.   if(hit)                           /* mousebutton pressed ? */
  301.     scndscr=TRUE;                   /* this means we are reading the next screen */
  302.  
  303. If the user pressed the left mousebutton, we leave the first screen.
  304. }
  305. --------------------------------------------------------------------------------
  306.  
  307. --------------------------------------------------------------------------------
  308. CleanUp()
  309. {
  310.   if(infile) fclose(infile);                     /* close the textfile */
  311.   if(screen) CloseScreen(screen);                /* give screen back.. */
  312.   if(IntuitionBase) CloseLibrary(IntuitionBase); /* don't need this libs anymore */
  313.   if(GfxBase) CloseLibrary(GfxBase);
  314.  
  315. We have to clean up the mess we made. (your mother doesn't work here...)
  316. Since we initialised the pointers to NULL, they won't be closed if
  317. the opening didn't succeed.
  318. }
  319. --------------------------------------------------------------------------------
  320.  
  321. --------------------------------------------------------------------------------
  322. _abort()
  323. { puts("-=INTERRUPTED=- user abort request");
  324.   /* user wants to quit by pressing [ctrl]C on keyboard */
  325.   CleanUp();        /* cleanup the system before */
  326.   exit(100);        /* exit with errornumber */
  327. }
  328.  
  329. This routine is called if the 'c' key with the controlkey is pressed.
  330. It substitutes the library routine abort(), therefore it's preceded with an _
  331. This routine probably won't work with other compilers than Aztec.
  332. --------------------------------------------------------------------------------
  333.  
  334. --------------------------------------------------------------------------------
  335. main(argc,argv)
  336. int argc;                        /* urgument count (1..n) */
  337. char *argv[];                    /* the values (0..n-1) */
  338.  
  339. We pass one command line parameter, the asciifilename.
  340. argc contains the number of parameters including the name of the program.
  341. argv[0] points to the name of the executed program.
  342. argv[1] points to the first parameter passed,ie the asciifilename.
  343. we will use argv[0] to check if the program was called TP or TPL,
  344. if the programname is TP, we execute the NTSC version, if the name
  345. is TPL, we execute the PAL version. So renameing the program influences
  346. it's behaviour.
  347.  
  348. { int xpos,ypos,len;             /* current x,y cursor position & length */        
  349.   char str[81];                  /* from the string stored int str */
  350.  
  351. Contains the string read in from the file.
  352. Since we read a line at a time + \0, we don't need any more storage.
  353.  
  354.   char ch;                       /* dummy character */
  355.  
  356.   if(argc!=2)                    /* more or less than 1 argument ? */ 
  357.   { puts("USAGE : TP(L) <ascii-file>");        /* display help */
  358.  
  359. Check the number of arguments passed
  360.  
  361.     CleanUp();                   /* cleanup and exit with error */
  362.     error=40;
  363.     goto Quit;
  364.   }
  365.  
  366.   infile=fopen(argv[1],"r");     /* try to open the specified file */
  367.  
  368. Open the requested file in read mode
  369.  
  370.   if(infile==NULL)               /* nop, not found... */
  371.   { puts("Can't open specified file");
  372.  
  373. Dos couldn't open/locate the file, cleanup and quit.
  374.  
  375.     CleanUp();
  376.     error=50;
  377.     goto Quit;
  378.   }
  379.  
  380.   /* this is kinda tricky:
  381.   since we have NTSC (200 scanlines) and PAL (256 scanlines) version Amy's
  382.   the name of the command defines the version you want to use. 
  383.   if you name the program :
  384.   TP  you are requesting the NTSC version.
  385.   TPL you are requesting the PAL version.
  386.   */
  387.  
  388.   BottomLine=201;                /* standard NTSC */
  389.   if(toupper(argv[0][2])=='L')   /* if command's 3th character is an L */
  390.   { BottomLine=257;              /* we want the large screen */
  391.     ns.Height=256;               /* redefine screen height */
  392.   }
  393.  
  394. This code does the NTSC/PAL trick.
  395. The NewScreen Height will be set to PAL if the 3th character from the
  396. programname is an 'L' or an 'l'.
  397. The Bottomline will be set accordingly to 200 or 256 plus the 1 offset
  398. for the starting ypos=17 location. We increase the scanlinenumber by 8,
  399. and with the odd 17 starting position, we want the testvalue of the bottemline
  400. to be odd either.
  401.  
  402.   Init();                        /* initialise the system */
  403.   if(error)                      /* error returned ? */
  404.     goto Quit;                        
  405.  
  406. If an error occured, go cleanup and quit.
  407.  
  408.   CLS();                         /* clear the screen */
  409.   xpos=0; ypos=17;               /* cursor position */
  410.   Move(rp,xpos,ypos);            /* go set the cursor */
  411.  
  412. Go to the starting cursor position
  413.  
  414.   while((ch=getc(infile)) != EOF)        /* read one char ahead to detect EOF */
  415.   { ungetc(ch,infile);                   /* put character back in buffer */
  416.     fgets(str,81,infile);                /* get a string of maximal 80+\0 chars */
  417.     len=strlen(str);                     /* calculate it's length */
  418.     if(len==80)                          /* buffer was full without reading a \0 */
  419.       len++;
  420.     Move(rp,xpos,ypos);                  /* move to cursor position */
  421.     Text(rp,str,--len);                  /* output the textline */
  422.     ypos+=8;                             /* 'linefeed' */
  423.     if(ypos==BottomLine)                 /* did we reach the bootom */
  424.     { NextScreen();                      /* yes, do the next screen */
  425.       ypos=17;                           /* cursor back to top */
  426.       if(error==90)                      /* did user want to quit ? */
  427.       { CleanUp();                       /* cleanup and quit */
  428.         goto Quit;
  429.       }
  430.       if(new)                            /* user wants to restart */
  431.       { new=FALSE;                       /* reset flags */
  432.         scndscr=FALSE;
  433.         if(fseek(infile,0L,0L))          /* goto start of file */
  434.           puts("Something wrong with seek");   /* how could this happen ? */
  435.       }
  436.     }
  437.   }
  438.  
  439. The code above should explain itself now i think.
  440.  
  441.   NextScreen();                          /* clear the last screen */
  442.   CleanUp();                             /* cleanup the theatre */
  443. Quit:
  444.   exit(error);
  445.  
  446. Back to caller (Dos shell i suppose) returning the errornumber
  447.  
  448. }
  449. --------------------------------------------------------------------------------
  450.  
  451. In the next issue i'll discuss the machinelanguage version of this program.
  452. The approach will be different.
  453. We won't open an intuition screen but a view, and we won't use dos to read
  454. the ascii file, but use the trackdisk.device which enables quik
  455. backreading in the file, so a real up and down browser will be included.
  456.  
  457. If you have any questions, here's my address:
  458. Jeroen K Sparla
  459. Ganzediepstraat 34
  460. 7523 PH  Enschede
  461. The Netherlands
  462.